package com.webrtc.demo.call

import android.content.Context
import android.content.Intent
import android.media.AudioManager
import android.os.Bundle
import android.os.Handler
import android.util.DisplayMetrics
import android.util.Log
import android.view.View
import android.widget.GridLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.forEach
import androidx.core.view.forEachIndexed
import com.webrtc.demo.ConnectionManager
import com.webrtc.demo.MultiCallHelper
import com.webrtc.demo.R
import com.webrtc.demo.util.ContactsUtils
import com.webrtc.demo.util.logD
import kotlinx.android.synthetic.main.activity_multi_call.*
import org.webrtc.*

class MultiCallActivity : AppCompatActivity() {

    companion object {
        private const val VIDEO_RESOLUTION_WIDTH = 1280
        private const val VIDEO_RESOLUTION_HEIGHT = 720
        private const val VIDEO_FPS = 30
        private const val TAG = "MultiCallActivity"

        const val TO_NAMES = "TO_NAMES"
        const val ROOM_ID = "ROOM_ID"
        const val CALLER_ID = "CALLER_ID"

        fun launch(
            context: Context,
            toNames: ArrayList<String>,
            roomId: String?,
            callerUid: String?
        ) {
            context.startActivity(
                Intent(
                    context.applicationContext,
                    MultiCallActivity::class.java
                ).putStringArrayListExtra(
                    TO_NAMES,
                    toNames
                )
                    .putExtra(ROOM_ID, roomId)
                    .putExtra(CALLER_ID, callerUid)
            )
        }
    }

    private val toNames: ArrayList<String> by lazy { intent.getStringArrayListExtra(TO_NAMES) }
    private val roomId: String by lazy { intent.getStringExtra(ROOM_ID) } // roomId 如果有传，说明自己是被呼叫方；否则自己是发起人
    private val isCaller: Boolean by lazy { intent.getStringExtra(ROOM_ID) == null }
    private val callerUid: String by lazy { intent.getStringExtra(CALLER_ID) }

    private val myId: String by lazy { ContactsUtils.getMyUid(this) }

    private val mRootEglBase: EglBase = ConnectionManager.rootEglBase

    private var mSurfaceTextureHelper: SurfaceTextureHelper? = null
    private lateinit var mVideoCapturer: VideoCapturer
    private lateinit var callHelper: MultiCallHelper

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_multi_call)

//        if (toNames.isEmpty()) {
//            throw java.lang.RuntimeException("无联系人")
//        }

        mVideoCapturer =
            createVideoCapturer() ?: throw RuntimeException("createVideoCapturer = null")
        mSurfaceTextureHelper =
            SurfaceTextureHelper.create(
                "CaptureThread",
                ConnectionManager.rootEglBase.eglBaseContext
            )

        logD(TAG, "创建MultiCallHelper，toNames=$toNames, roomId=$roomId, caller=$callerUid")

        val surfaceViews = mutableMapOf<String, SurfaceViewRenderer>()
        callHelper =
            MultiCallHelper(
                myId,
                toNames,
                roomId,
                callerUid,
                object : MultiCallHelper.MutiCallUserListener {

                    override fun onLocalCapturerObserver(observer: CapturerObserver) {
                        runOnUiThread {
                            mVideoCapturer.initialize(
                                mSurfaceTextureHelper,
                                applicationContext,
                                observer
                            )

                            capturerInitialized = true

                            if (resume)
                                startCapture()
                        }
                    }

                    override fun onBindSurface(uid: String): SurfaceViewRenderer {

                        logcat("创建 $uid 的Surface")

                        val v = createSurfaceView()
                        surfaceViews[uid] = v
                        runOnUiThread {
                            gridLayout.addView(v)
                            requestSurfaceLayout()
                        }
                        return v
                    }

                    override fun onUnBindSurface(surface: SurfaceViewRenderer) {
                        surface.release()
                        runOnUiThread {
                            gridLayout.removeView(surface)
                            requestSurfaceLayout()
                        }
                    }

                    override fun onUserDeny(uid: String) {
                        logOnUI("$uid 拒绝了你的连接请求")
                    }
                })


        // NOTE: this _must_ happen while PeerConnectionFactory is alive!
        Logging.enableLogToDebugOutput(Logging.Severity.LS_VERBOSE)

        btn_video_close.setOnClickListener {
            stopCapturer = !stopCapturer
            if (stopCapturer) {
                mVideoCapturer.stopCapture()
                logOnUI("已关闭视频")
                btn_video_close.text = "打开视频"

            } else {
                mVideoCapturer.startCapture(
                    VIDEO_RESOLUTION_WIDTH,
                    VIDEO_RESOLUTION_HEIGHT,
                    VIDEO_FPS
                )
                logOnUI("已打开视频")
                btn_video_close.text = "关闭视频"
            }
        }

        btn_switch_camera.setOnClickListener { btn ->
            val vc = mVideoCapturer
            if (vc is CameraVideoCapturer) {
                btn.isEnabled = false
                vc.switchCamera(object : CameraVideoCapturer.CameraSwitchHandler {
                    override fun onCameraSwitchDone(p0: Boolean) {
                        runOnUiThread {
                            btn.isEnabled = true
                            logOnUI("切换摄像头成功")
                        }
                    }

                    override fun onCameraSwitchError(p0: String?) {
                        runOnUiThread {
                            btn.isEnabled = true
                            logOnUI("切换摄像头失败")
                        }
                    }
                })
            }
        }

        btn_voice_close.setOnClickListener {
            val audioTrack = callHelper.otherMediaConnections.values.first().localAudioTrack
            if (audioTrack is MediaStreamTrack) {
                val oldEnabled = audioTrack.enabled()
                audioTrack.setEnabled(!oldEnabled)
                logOnUI("已${if (oldEnabled) "关闭" else "打开"}麦克风")
                btn_voice_close.text = "${if (oldEnabled) "打开" else "关闭"}麦克风"
            }
        }

        btn_sound_switch.setOnClickListener {
            val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
            if (audioManager.mode == AudioManager.MODE_NORMAL) {
                audioManager.isSpeakerphoneOn = false
                audioManager.mode = AudioManager.MODE_IN_COMMUNICATION
                logOnUI("已启用听筒")
                btn_sound_switch.text = "使用扬声器"
                audioManager.setStreamVolume(
                    AudioManager.STREAM_VOICE_CALL,
                    audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL),
                    AudioManager.FX_KEY_CLICK
                );
            } else {
                audioManager.isSpeakerphoneOn = true
                audioManager.mode = AudioManager.MODE_NORMAL
                //设置音量，解决有些机型切换后没声音或者声音突然变大的问题
                audioManager.setStreamVolume(
                    AudioManager.STREAM_SYSTEM,
                    audioManager.getStreamVolume(AudioManager.STREAM_SYSTEM),
                    AudioManager.FX_KEY_CLICK
                )
                logOnUI("已启用扬声器")
                btn_sound_switch.text = "使用听筒"
            }

        }
    }

    private var stopCapturer = false
        set(value) {
            field = value
            btn_switch_camera.isEnabled = !value
        }

    private var capturerInitialized = false
        set(value) {
            if (field == value) return
            field = value
            if (value) {
                btn_video_close.isEnabled = true
                btn_switch_camera.isEnabled = true
            }
        }
    private var resume = false

    private fun createSurfaceView(): SurfaceViewRenderer {
        val view = SurfaceViewRenderer(this)
        runOnUiThread {
            initSurfaceView(view)
        }
        return view
    }

    private fun requestSurfaceLayout() {
        val columnCount = if (gridLayout.childCount > 4) 3 else 2
        val displayMetrics = DisplayMetrics()
        windowManager.defaultDisplay.getMetrics(displayMetrics)
        val surfaceHeight = displayMetrics.widthPixels / columnCount
        gridLayout.forEachIndexed { index, view ->
            val lp = view.layoutParams as GridLayout.LayoutParams
            lp.run {
                val rowStart = index / columnCount
                val columnStart = index % columnCount
                rowSpec = GridLayout.spec(rowStart, 1f)
                columnSpec = GridLayout.spec(columnStart, 1f)
                width = 0
                height = surfaceHeight
                setMargins(0, 0, 0, 0)
                if (columnStart != 0) {
                    leftMargin = 1
                }
                if (columnStart != columnCount - 1) {
                    rightMargin = 1
                }
                if (rowStart != 0) {
                    topMargin = 1
                }
                if (rowStart != gridLayout.childCount / columnCount) {
                    bottomMargin = 1
                }
            }
        }
        gridLayout.columnCount = columnCount
    }

    private fun logOnUI(msg: String) {
        runOnUiThread {
            logcatTv.text = logcatTv.text.toString() + "\n" + msg
        }
    }

    private fun initSurfaceView(view: SurfaceViewRenderer) {
        view.init(mRootEglBase.eglBaseContext, null)
        view.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL)
        view.setMirror(true)
        view.setEnableHardwareScaler(false /* enabled */)

//        mLocalSurfaceView!!.init(ConnectionManager.rootEglBase.eglBaseContext, null)
//        mLocalSurfaceView!!.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL)
//        mLocalSurfaceView!!.setMirror(true)
//        mLocalSurfaceView!!.setEnableHardwareScaler(false /* enabled */)
//
//        mRemoteSurfaceView!!.init(ConnectionManager.rootEglBase.eglBaseContext, null)
//        mRemoteSurfaceView!!.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL)
//        mRemoteSurfaceView!!.setMirror(true)
//        mRemoteSurfaceView!!.setEnableHardwareScaler(true /* enabled */)
//        mRemoteSurfaceView!!.setZOrderMediaOverlay(true)

//        val videoSink = ProxyVideoSink()
//        videoSink.setTarget(view)
//        mVideoTrack.addSink(videoSink)
    }

    private fun releaseAllSurfaceView() {
        gridLayout.forEach {
            (it as SurfaceViewRenderer).release()
        }
    }

    private fun startCapture() {
//        val videoSink =
//            ProxyVideoSink()
//        videoSink.setTarget(view)
//        mPeerConnectionFactory = createPeerConnectionFactory(this)
//        // NOTE: this _must_ happen while PeerConnectionFactory is alive!
//        Logging.enableLogToDebugOutput(Logging.Severity.LS_VERBOSE)
//        mVideoCapturer =
//            createVideoCapturer() ?: throw RuntimeException("createVideoCapturer = null")
//        mSurfaceTextureHelper =
//            SurfaceTextureHelper.create("CaptureThread", mRootEglBase.getEglBaseContext())
//        val videoSource = mPeerConnectionFactory!!.createVideoSource(false)
//        mVideoCapturer.initialize(
//            mSurfaceTextureHelper,
//
//            applicationContext,
//            videoSource.capturerObserver
//        )
//        mVideoTrack = mPeerConnectionFactory!!.createVideoTrack(
//            VIDEO_TRACK_ID,
//            videoSource
//        )
//        mVideoTrack.setEnabled(true)
//        mVideoTrack.addSink(videoSink)
//        val audioSource = mPeerConnectionFactory!!.createAudioSource(
//            MediaConstraints()
//        )
//        mAudioTrack = mPeerConnectionFactory!!.createAudioTrack(
//            AUDIO_TRACK_ID,
//            audioSource
//        )
//        mAudioTrack.setEnabled(true)

        mVideoCapturer.startCapture(
            VIDEO_RESOLUTION_WIDTH,
            VIDEO_RESOLUTION_HEIGHT,
            VIDEO_FPS
        )
    }

    override fun onResume() {
        super.onResume()

        resume = true

        if (capturerInitialized)
            startCapture()

//        if (!init) {
//            init = true
//            if (isCaller) {
//                // 发起呼叫
//                startCallBtn.visibility = View.GONE
//                endCallBtn.visibility = View.VISIBLE
//                RTCSignalClient.sendNegotiate(toName, Negotiate.CALL, mediaType = MediaType.VIDEO) {
//                    logcatOnUI("call send success")
//                }
//            } else {
//                // 确认连线
//                RTCSignalClient.sendNegotiate(toName, Negotiate.ACK, mediaType = MediaType.VIDEO) {
//                    logcatOnUI("ack send success")
//                }
//                startCallBtn.visibility = View.GONE
//                endCallBtn.visibility = View.VISIBLE
//            }
//        }
//
//        mVideoCapturer.startCapture(
//            VIDEO_RESOLUTION_WIDTH,
//            VIDEO_RESOLUTION_HEIGHT,
//            VIDEO_FPS
//        )
    }

    override fun onPause() {
        super.onPause()
        try {
            mVideoCapturer.stopCapture()
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        doEndCall()
        handler.removeCallbacksAndMessages(null)
        releaseAllSurfaceView()
        mVideoCapturer.dispose()
        mSurfaceTextureHelper!!.dispose()
        PeerConnectionFactory.stopInternalTracingCapture()
        PeerConnectionFactory.shutdownInternalTracer()
    }

    class ProxyVideoSink : VideoSink {
        private var mTarget: VideoSink? = null

        @Synchronized
        override fun onFrame(frame: VideoFrame) {
            if (mTarget == null) {
                Log.d(
                    TAG,
                    "Dropping frame in proxy because target is null."
                )
                return
            }
            mTarget!!.onFrame(frame)
        }

        @Synchronized
        fun setTarget(target: VideoSink?) {
            mTarget = target
        }
    }

    fun onClickStartCallButton(v: View?) {
        // doStartCall()
    }

    fun onClickEndCallButton(v: View?) {
        doEndCall()
        finishDelay()
    }

//    private fun updateCallState(idle: Boolean) {
//        runOnUiThread(Runnable {
//            if (idle) {
//                startCallBtn.visibility = View.VISIBLE
//                endCallBtn.visibility = View.GONE
//                mRemoteSurfaceView!!.visibility = View.GONE
//            } else {
//                startCallBtn.visibility = View.GONE
//                endCallBtn.visibility = View.VISIBLE
//                mRemoteSurfaceView!!.visibility = View.VISIBLE
//            }
//        })
//    }

//    private fun doStartCall() {
//        logcatOnUI("Start Call, Wait ...")
//        // empty
//    }

    private fun doEndCall() {
        logcat("End Call, Wait ...")
        callHelper.close()
        hanup()
    }

    private fun hanup() {
        logcat("Hanup Call, Wait ...")
        callHelper.leave()
        logcat("Hanup Done.")
    }

    /*
     * Read more about Camera2 here
     * https://developer.android.com/reference/android/hardware/camera2/package-summary.html
     **/
    private fun createVideoCapturer(): VideoCapturer? {
        return if (Camera2Enumerator.isSupported(this)) {
            createCameraCapturer(Camera2Enumerator(this))
        } else {
            createCameraCapturer(Camera1Enumerator(true))
        }
    }

    private fun createCameraCapturer(enumerator: CameraEnumerator): VideoCapturer? {
        val deviceNames = enumerator.deviceNames
        // First, try to find front facing camera
        Log.d(TAG, "Looking for front facing cameras.")
        for (deviceName in deviceNames) {
            if (enumerator.isFrontFacing(deviceName)) {
                Logging.d(
                    TAG,
                    "Creating front facing camera capturer."
                )
                val videoCapturer: VideoCapturer? = enumerator.createCapturer(deviceName, null)
                if (videoCapturer != null) {
                    return videoCapturer
                }
            }
        }
        // Front facing camera not found, try something else
        Log.d(TAG, "Looking for other cameras.")
        for (deviceName in deviceNames) {
            if (!enumerator.isFrontFacing(deviceName)) {
                Logging.d(TAG, "Creating other camera capturer.")
                val videoCapturer: VideoCapturer? = enumerator.createCapturer(deviceName, null)
                if (videoCapturer != null) {
                    return videoCapturer
                }
            }
        }
        return null
    }

    private val handler = Handler()

    private fun finishDelay() {
        handler.postDelayed({
            finish()
        }, 500)
    }

    private fun logcat(msg: String) {
        Log.d(TAG, msg)
    }

}